package org.feng.utils;


import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author by feng
 * @des 树状结构
 * @date 2021/4/27 14:03
 */
public class TreeUtil {

    private TreeUtil() {
    }

    /**
     * 把List 变形为 树状结构
     * 默认   主键id为：id 父id为：parentId   实体内必须包含一个List<具体实体类> 类型的字段 默认为：children
     *
     * @param list 列表数据
     * @param <T>
     * @return
     */
    public static <T> List<T> tree(List<T> list) {
        try {
            Map<Object, T> menuMap = new LinkedHashMap<>();
            for (T t : list) {
                menuMap.put(classGetField(t, "id"), t);
            }
            for (T t : list) {
                Long parentId = (Long) classGetField(t, "parentId");
                if (parentId != 0) {
                    T entity = menuMap.get(parentId);
                    if (entity != null) {
                        List<T> entityList = (List<T>) classGetField(entity, "children");
                        if (entityList == null) {
                            entityList = new ArrayList<>();
                        }
                        entityList.add(t);
                        classSetField(entity, "children", entityList);
                    }
                }
            }
            List<Object> entityList = new ArrayList<>();
            for (Map.Entry<Object, T> entry : menuMap.entrySet()) {
                Object t = entry.getKey();
                Long parentId = (Long) classGetField(entry.getValue(), "parentId");
                if (parentId != 0) {
                    entityList.add(t);
                }
            }
            for (Object i : entityList) {
                menuMap.remove(i);
            }
            return new ArrayList<>(menuMap.values());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }


    public static <T> List<T> tree(List<T> list, String parentIdFieldName, String childrenFieldName) {
        try {
            Map<Object, T> menuMap = new LinkedHashMap<>();
            for (T t : list) {
                menuMap.put(classGetField(t, "id"), t);
            }
            for (T t : list) {
                Long parentId = (Long) classGetField(t, parentIdFieldName);
                if (parentId != 0) {
                    T entity = menuMap.get(parentId);
                    if (entity != null) {
                        List<T> entityList = (List<T>) classGetField(entity, childrenFieldName);
                        if (entityList == null) {
                            entityList = new ArrayList<>();
                        }
                        entityList.add(t);
                        classSetField(entity, childrenFieldName, entityList);
                    }
                }
            }
            List<Object> entityList = new ArrayList<>();
            for (Map.Entry<Object, T> entry : menuMap.entrySet()) {
                Object t = entry.getKey();
                Long parentId = (Long) classGetField(entry.getValue(), parentIdFieldName);
                if (parentId != 0) {
                    entityList.add(t);
                }
            }
            for (Object i : entityList) {
                menuMap.remove(i);
            }
            return new ArrayList<>(menuMap.values());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 获取实体某个字段的值
     *
     * @param t     实体
     * @param field 字段名
     * @param <T>   泛型
     * @return
     * @throws Exception
     */
    private static <T> Object classGetField(T t, String field) throws Exception {
        Class<?> entityClass = t.getClass();
        Field f = null;
        try {
            f = entityClass.getDeclaredField(field);
        } catch (NoSuchFieldException e) {
            Class<?> superclass = entityClass.getSuperclass();
            f = superclass.getDeclaredField(field);
        }
        Method rM = new PropertyDescriptor(f.getName(), entityClass).getReadMethod();
        return rM.invoke(t);
    }

    /**
     * set实体某个字段的值
     *
     * @param t     实体
     * @param field 字段名
     * @param data  数据
     * @param <T>   泛型
     * @return
     * @throws Exception
     */
    private static <T> void classSetField(T t, String field, Object data) throws Exception {
        Class<?> entityClass = t.getClass();
        Field f = entityClass.getDeclaredField(field);
        Method rM = new PropertyDescriptor(f.getName(), entityClass).getWriteMethod();
        rM.invoke(t, data);
    }

}
